/**
 * @file lib_syscall.h
 * @author lcz (you@domain.com)
 * @brief
 * @version 0.1
 * @date 2022-10-31
 *
 * @copyright Copyright (c) 2022
 *
 */

#ifndef LIB_SYSCALL_H
#define LIB_SYSCALL_H

#include "os.cfg.h"
#include "comm/types.h"
#include <sys/stat.h>



/**
 * @brief 定义系统调用的参数类型，暂定五个参数
 *
 */
typedef struct _syscall_args_t
{
    int id; // id判断调用的函数
    int arg0;
    int arg1;
    int arg2;
    int arg3;
} syscall_args_t;

/**
 * @brief 执行系统调用，进行参数的压栈，由此函数将由特权级0进入特权级3
 *
 * @param args 参数结构体
 * @return * void
 */
static inline int sys_call(syscall_args_t *args)
{
    int ret;
    uint32_t addr[] = {0,
                       SELECTOR_SYSCAL | 0};
    // 0 is rpl , 手动压入，自动复制好吧
    // lcalll 系统调用的参数复制在特权级3于特权级0之间
    // 采用调用门, 这里只支持5个参数
    // 用调用门的好处是会自动将参数复制到内核栈中，这样内核代码很好取参数
    // 而如果采用寄存器传递，取参比较困难，需要先压栈再取
    __asm__ __volatile(
        "push %[arg3]\n\t"
        "push %[arg2]\n\t"
        "push %[arg1]\n\t"
        "push %[arg0]\n\t"
        "push %[id]\n\t"
        "lcalll *(%[a])"
        : "=a"(ret)
        : [arg3] "r"(args->arg3),
          [arg2] "r"(args->arg2),
          [arg1] "r"(args->arg1),
          [arg0] "r"(args->arg0),
          [id] "r"(args->id),
          [a] "r"(addr)

    );
    return ret;
}
// 进程相关
void msleep(int ms);
int getpid(void);
void print_msg(const char *fmt, int arg);
int fork(void);
int execve(const char *name, char *const *argv, char *const *env);
int yield(void);
void _exit(int status);
int wait(int *status);

// 文件系统的调用
int open(const char *name, int flags, ...);
int read(int file, char *ptr, int len);
int write(int file, char *ptr, int len);
int close(int file);
int lseek(int file, int ptr, int dir);

// newlib库相关底层接口
int isatty(int file);
int fstat(int file, struct stat *st);
void *sbrk(ptrdiff_t incr);
int dup(int file);

// 文件目录

// 目录下的项包含文件类型或目录类型
typedef struct _dirent
{
    // 索引
    int index;
    int type;
    char name[256];
    int size;
} dirent;

// 目录
typedef struct _DIR
{
    int index;
    struct _dirent dirent;
} DIR;

// 系统调用接口函数
DIR *opendir(const char *path);
struct dirent *readdir(DIR *dir);
int closedir(DIR *dir);


// 系统调用接口，控制回显
int ioctl(int file, int cmd, int arg0, int arg1);

int unlink(const char *path_name);

#endif
